home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / AOCE Sample Code / PowerTalk Access Modules / Sample SMSAM / SampleSMSAM Source / ThreadStuff / ThreadClasses.cp < prev    next >
Encoding:
Text File  |  1995-07-28  |  24.2 KB  |  942 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ThreadClasses.cp
  3.  
  4.     Copyright:    © 1991-1994 by Apple Computer, Inc.
  5.                 All rights reserved.
  6.  
  7.     Part of the AOCE Sample SMSAM Package.  Consult the license
  8.     which came with this software for your specific legal rights.
  9.  
  10. */
  11.  
  12.  
  13.  
  14. /***********************************|****************************************/
  15.  
  16. #ifndef __BLJSTANDARDINCLUDES__
  17. #include "BLJStandardIncludes.h"
  18. #endif
  19.  
  20. #ifndef __DEBUGGINGGEAR__
  21. #include <DebuggingGear.h>
  22. #endif
  23.  
  24. #ifndef __FAILURE__
  25. #include "Failure.h"
  26. #endif
  27.  
  28. #ifndef __GESTALTEQU__
  29. #include <GestaltEqu.h>
  30. #endif
  31.  
  32. #ifndef __GRAFPORTSAVER__
  33. #include "GrafPortSaver.h"
  34. #endif
  35.  
  36. #ifndef __LIMITS__
  37. #include <Limits.h>
  38. #endif
  39.  
  40. #ifndef __LOGWINDOW__
  41. #include "LogWindow.h"
  42. #endif
  43.  
  44. #ifndef __OBJECTLIST__
  45. #include "ObjectList.h"
  46. #endif
  47.  
  48. #ifndef __STRSTREAM__
  49. #include "StrStream.h"
  50. #endif
  51.  
  52. #ifndef __THREADS__
  53. #include "Threads.h"
  54. #endif
  55.  
  56. #ifndef __THREADCLASSES__
  57. #include "ThreadClasses.h"
  58. #endif
  59.  
  60. //    This macro 'references' a variable, so that a '# warning:  variable not used' warning is not
  61. //    generated during a compile.  This macro should not cause any code to be generated.
  62. #ifndef __UNUSED__
  63. #define unused(x) ((void) &x)
  64. #define __UNUSED__
  65. #endif
  66.  
  67.  
  68. /***********************************|****************************************/
  69. /***********************************|****************************************/
  70.  
  71. class TThreadStatusWindow : public TLogWindow
  72. {
  73. public:                                TThreadStatusWindow ( short windowID );
  74.         virtual                        ~TThreadStatusWindow ( );
  75.                                     
  76.         virtual void                Show () const;
  77.         
  78.         virtual void                DrawRow ( unsigned long whichRow ) const;
  79.         virtual void                RedrawSleeping ( ) const;
  80.         
  81.         virtual unsigned long        GetRowCount () const;
  82.         virtual unsigned long        GetRowWidth ( ) const;
  83. };
  84.  
  85. /***********************************|****************************************/
  86.  
  87. #if debug
  88.  
  89. Boolean                        IsThreadStatusDialogVisible ( );
  90. void                        ShowThreadStatusDialog ( );
  91. void                        HideThreadStatusDialog ( );
  92. Boolean                        HandleThreadStatusEvent ( EventRecord& event );
  93.  
  94. TThreadStatusWindow*        gThreadStatusWindow = nil;
  95. #endif
  96.  
  97. /***********************************|****************************************/
  98.  
  99. DeclareList(TThreadManagerThread,TThreadManagerThreadSharedList);
  100. ImplementList(TThreadManagerThread,TThreadManagerThreadSharedList,false);
  101.  
  102. /***********************************|****************************************/
  103.  
  104. unsigned long                    gTickWhenNextThreadNeedsToBeWoken = ULONG_MAX;
  105. TThreadManagerThreadSharedList    gSleepingThreads;
  106.  
  107. /***********************************|****************************************/
  108.  
  109. void ChangeActiveThreadInThreadStatusWindow ( WindowPtr windowP, TThread * newThread );
  110. void UpdateThreadStatusWindow ( WindowPtr windowP );
  111.  
  112. /***********************************|****************************************/
  113.  
  114. inline unsigned long min ( unsigned long a, unsigned long b )
  115. {
  116.     return ( a < b ) ? a : b ;
  117. }
  118.  
  119. /***********************************|****************************************/
  120.  
  121. Boolean IsThreadStatusDialogVisible ( )
  122. {
  123.     return false;
  124. }
  125.  
  126. /***********************************|****************************************/
  127.  
  128. void ShowThreadStatusDialog ( )
  129. {
  130.     #if 1
  131.     if ( ! gThreadStatusWindow )
  132.     {
  133.         gThreadStatusWindow = new TThreadStatusWindow ( 2001 );
  134.         gThreadStatusWindow->Show();
  135.         
  136.         gThreadStatusWindow->InsertRow( 1, TThread::GetThreadCount () );
  137.     }
  138.     
  139.     gThreadStatusWindow->Show ();
  140.     #endif
  141. }
  142.  
  143. /***********************************|****************************************/
  144.  
  145. void HideThreadStatusDialog ( )
  146. {
  147.     if ( gThreadStatusWindow )
  148.     {
  149.         delete gThreadStatusWindow ;
  150.         gThreadStatusWindow = nil;
  151.     }
  152. }
  153.  
  154. /***********************************|****************************************/
  155. /***********************************|****************************************/
  156.  
  157. void TSleep ( unsigned long x ) 
  158. {
  159.     unused(x);
  160.     TThread* aThread = TThread::GetCurrentThread();
  161.  
  162.     if ( aThread )
  163.         aThread->Sleep( x );
  164. }
  165.  
  166. /***********************************|****************************************/
  167.  
  168. void TYield()
  169. {
  170.     TThread* aThread = TThread::GetCurrentThread();
  171.     
  172.     if ( aThread )
  173.         aThread->Yield();
  174. }
  175.  
  176. /***********************************|****************************************/
  177.             
  178. void TSetRefCon(OSType x) 
  179. {
  180.     unused(x);
  181. }
  182.  
  183. /***********************************|****************************************/
  184.  
  185. OSType TGetRefCon()
  186. {
  187.     TThread* aThread = TThread::GetCurrentThread();
  188.     
  189.     if ( aThread )
  190.         return aThread->GetDescriptor();
  191.     else
  192.         return '\?\?\?\?';
  193. }
  194.  
  195. /***********************************|****************************************/
  196.  
  197. TThread*    createThread(OSType name, 
  198.                     void* proc, unsigned long stkSize, 
  199.                     unsigned long p1, unsigned long p2, 
  200.                     short execMode)
  201. {
  202.     unused(stkSize); unused(execMode);
  203.     return new TThreadManagerThread ( (FNULUL) proc, p1, p2, name );
  204. }
  205.  
  206. /***********************************|****************************************/
  207.  
  208. #if debug
  209. ostream& TThread::operator << ( ostream& s )
  210. {    OSType threadDescriptor = GetDescriptor();
  211.     s << "TThreadManagerThread:'";
  212.     s.write ( (char*) & threadDescriptor, sizeof( threadDescriptor ) );
  213.     s << "' " << flush;
  214.  
  215.     return s;
  216. }
  217. #endif
  218.  
  219. /***********************************|****************************************/
  220.  
  221. DeclareList ( TThread, TThreadList );
  222. ImplementList ( TThread, TThreadList, false );
  223.  
  224. /***********************************|****************************************/
  225.  
  226. TThread * TThread::gCurrentThread = nil;
  227. TThread * TThread::gThreadList = nil;
  228.  
  229. TThreadList            gThreadStatusWindowList;
  230.  
  231. /***********************************|****************************************/
  232.  
  233.  
  234. /***********************************|****************************************/
  235. /***********************************|****************************************/
  236. /***********************************|****************************************/
  237.  
  238. static pascal void ThreadPBCallAsyncCompletion ( )
  239. {
  240. }
  241.  
  242. /***********************************|****************************************/
  243.  
  244. typedef    pascal    OSErr    (*FNPBB)(ParmBlkPtr, Boolean);
  245.  
  246. /***********************************|****************************************/
  247.  
  248. OSErr ThreadPBCallAsync ( FNPBB functionToCall, ParmBlkPtr pb )
  249. {
  250.     typedef struct {
  251.         ParmBlkPtr thePB;
  252.         TThread* theThread;
  253.     } ThreadInfo;
  254.     
  255.     ThreadInfo        info;
  256.     
  257.     info.thePB = pb;
  258.     info.theThread = TThread::GetCurrentThread();
  259.  
  260.     info.theThread->BeginCritical ();
  261.     OSErr err = ( *functionToCall ) ( pb, false );
  262.     info.theThread->EndCritical ();
  263.         
  264.     return err;
  265. }
  266.  
  267. /***********************************|****************************************/
  268.  
  269. TThread::TThread ( )
  270. {
  271.     //    Create a thread, and insert this thread descriptor into the linked list of
  272.     //    all threads.
  273.     fNext = gThreadList;
  274.     gThreadList = this;
  275.     
  276.     //    Insert this thread into the thread status window.
  277.     #if debug
  278.     gThreadStatusWindowList.Append ( this );
  279.     if ( gThreadStatusWindow )
  280.         gThreadStatusWindow->InsertRow ( 1 );
  281.     #endif
  282. }
  283.  
  284. /***********************************|****************************************/
  285.  
  286. TThread::~TThread ( )
  287. {
  288.     //    Remove this thread from the linked list of all threads.
  289.     if ( gThreadList == this )
  290.     {
  291.         gThreadList = this->fNext;
  292.     }
  293.     else
  294.     {    TThread *prevThread = gThreadList;
  295.     
  296.         while ( prevThread && ( prevThread->fNext != this ) )
  297.             prevThread = prevThread->fNext;
  298.         
  299.         if ( prevThread )
  300.             prevThread->fNext = prevThread->fNext->fNext;
  301.     }
  302.     
  303.     #if debug
  304.     gThreadStatusWindowList.Remove ( this );
  305.     #endif
  306. }
  307.  
  308. /***********************************|****************************************/
  309. /***********************************|****************************************/
  310. /***********************************|****************************************/
  311.  
  312. pascal unsigned long TThreadInstantiationWrapper ( TThreadManagerThread* thread )
  313. {
  314.     ::SetExceptionChain ( (void*) nil );
  315.     
  316.     TRY
  317.         (*thread->fThreadEntry ) ( (unsigned long) thread->fParam1, (unsigned long) thread->fParam2 );
  318.         
  319.     EXCEPTION
  320.         keith << "TThread::Failure to top level of thread "; OutputOSType ( keith, thread->fDescriptor ); keith << endl;
  321.     
  322.     ENDEXCEPTION
  323.  
  324.     return 0;
  325. }
  326.  
  327. /***********************************|****************************************/
  328.  
  329. pascal void TThreadManagerThread::ThreadManagerSwitchInProc ( ThreadID /* threadBeingSwitched */, void* switchProcParam )
  330. {
  331.     TThreadManagerThread* thread = ( TThreadManagerThread *) switchProcParam;
  332.     
  333.     if ( thread )
  334.     {    unsigned long savedA5 = SetA5 ( thread->fA5 );
  335.         
  336.         ::SetExceptionChain ( thread->GetExceptionChain() );
  337.     
  338.         gCurrentThread = thread;
  339.         
  340.         #if 0
  341.         if ( gThreadStatusWindow )
  342.             gThreadStatusWindow->InvalidateRow ( gThreadStatusWindowList.Find ( thread ) );
  343.         #endif
  344.  
  345.         SetA5 ( savedA5 );
  346.     }
  347. }
  348.  
  349. /***********************************|****************************************/
  350.  
  351. pascal void TThreadManagerThread::ThreadManagerSwitchOutProc ( ThreadID /* threadBeingSwitched */, void* switchProcParam )
  352. {
  353.     TThreadManagerThread * thread = ( TThreadManagerThread *) switchProcParam;
  354.  
  355.     if ( thread )
  356.     {    unsigned long savedA5 = SetA5 ( thread->fA5 );
  357.         
  358.         thread->SetExceptionChain ( ::GetExceptionChain() );
  359.         ::SetExceptionChain ( nil );
  360.     
  361.         #if 0
  362.         if ( gThreadStatusWindow )
  363.             gThreadStatusWindow->InvalidateRow ( gThreadStatusWindowList.Find ( thread ) );
  364.         #endif
  365.         
  366.         SetA5 ( savedA5 );
  367.     }
  368. }
  369.  
  370. /***********************************|****************************************/
  371.  
  372. pascal void TThreadManagerThread::TThreadManagerThreadTerminationProc ( ThreadID /* threadID */, void * terminationProcParam )
  373. {
  374.     TThreadManagerThread * thread = ( TThreadManagerThread * ) terminationProcParam;
  375.     
  376.     if ( thread )
  377.     {    unsigned long savedA5 = SetA5 ( thread->fA5 );
  378.     
  379.         #if debug
  380.         if ( gThreadStatusWindow )
  381.             gThreadStatusWindow->DeleteRow ( gThreadStatusWindowList.Find ( thread ) );
  382.         #endif
  383.  
  384.         //    Change the thread so that our destructor won't try to delete it.        
  385.         thread->fThreadID = kNoThreadID;    
  386.         delete thread;
  387.  
  388.         SetA5 ( savedA5 );
  389.     }
  390. }
  391.  
  392. /***********************************|****************************************/
  393. /***********************************|****************************************/
  394.  
  395. TThreadManagerThread::TThreadManagerThread ( FNULUL proc, unsigned long param1, unsigned long param2, OSType descriptor ) :
  396.     fDescriptor ( descriptor ),
  397.     fExceptionChainTop ( nil ),
  398.     fA5 ( SetCurrentA5 () )
  399. {
  400.     fThreadEntry = proc;
  401.     
  402.     fParam1 = param1;
  403.     fParam2 = param2;
  404.         
  405.     OSErr err = NewThread ( kCooperativeThread, (ThreadEntryProcPtr) &TThreadInstantiationWrapper, this, 0, kCreateIfNeeded, nil, &fThreadID );
  406.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) ThreadManagerSwitchInProc, (void*) this, true );
  407.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) ThreadManagerSwitchOutProc, (void*) this, false );
  408.     SetThreadTerminator ( fThreadID, (ThreadTerminationProcPtr) TThreadManagerThreadTerminationProc, (void*) this );
  409.     
  410.     if ( err )
  411.         keith << "TThreadManagerThreadTThread(), err = " << err << endl;
  412. }
  413.  
  414. /***********************************|****************************************/
  415.  
  416. TThreadManagerThread::TThreadManagerThread ( OSType descriptor ) :
  417.     fDescriptor ( descriptor ),
  418.     fExceptionChainTop ( nil ),
  419.     fThreadID ( kApplicationThreadID ),
  420.     fThreadEntry ( nil ),
  421.     fParam1 ( 0 ),
  422.     fParam2 ( 0 ),
  423.     fA5 ( SetCurrentA5 () )    
  424. {
  425.     OSErr err = ::GetCurrentThread ( & fThreadID);
  426.  
  427.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) ThreadManagerSwitchInProc, (void*) this, true );
  428.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) ThreadManagerSwitchOutProc, (void*) this, false );
  429.     SetThreadTerminator ( fThreadID, (ThreadTerminationProcPtr) TThreadManagerThreadTerminationProc, (void*) this );
  430. }    
  431.  
  432. /***********************************|****************************************/
  433.  
  434. TThreadManagerThread::~TThreadManagerThread ( )
  435. {    
  436.     //    Make sure we're not in the list of sleeping threads.
  437.     gSleepingThreads.Remove ( this );
  438.     
  439.     //    And delete our actual thread if it hasn't already been deleted.
  440.     ThreadID threadID = fThreadID;
  441.     fThreadID = kNoThreadID;
  442.     if ( threadID != kNoThreadID )
  443.         DisposeThread ( threadID, 0, true );
  444. }
  445.  
  446. /***********************************|****************************************/
  447.  
  448. static unsigned long TicksUntil ( unsigned long tick )
  449. {
  450.     unsigned long now = TickCount ();
  451.     
  452.     if ( tick < now )
  453.         return 0;
  454.     else
  455.         return tick - now;
  456. }
  457.  
  458. /***********************************|****************************************/
  459.  
  460. #if debug
  461. ostream& TThreadManagerThread::operator << ( ostream& s )
  462. {    OSType threadDescriptor = GetDescriptor();
  463.     s << "TThread:'";
  464.     s.write ( (char*) & threadDescriptor, sizeof( threadDescriptor ) );
  465.     s << "' ";
  466.     
  467.     //    Display the state of the thread.
  468.     ThreadState state;
  469.     OSErr err = GetThreadState ( fThreadID, & state );
  470.     if ( err == noErr )
  471.     {
  472.         switch ( state )
  473.         {
  474.             case kReadyThreadState:
  475.                 s << "Ready    "; 
  476.                 break;
  477.                 
  478.             case kStoppedThreadState:
  479.                  s << "Sleeping (" << 
  480.                      TicksUntil ( fWakeThreadAfter ) / 60 <<
  481.                      " secs longer) ";
  482.                  break;
  483.                  
  484.             case kRunningThreadState:
  485.                  s << "Running  ";
  486.                  break;
  487.                  
  488.             default:
  489.                 s << "(Unknown state=" << state << ") ";
  490.                 break;
  491.         };
  492.     }
  493.     else
  494.     {
  495.         s << "(Error " << err << " getting state) ";
  496.     }
  497.     
  498.     //    Display the amount of stack space available to the thread.
  499.     unsigned long stackSize;
  500.     err = ThreadCurrentStackSpace ( fThreadID, & stackSize );
  501.     s << " Stack:" << stackSize << " " << (char) 0;
  502.  
  503.     return s;
  504. }
  505. #endif
  506.  
  507. /***********************************|****************************************/
  508.  
  509. void TThreadManagerThread::Sleep ( unsigned long howLongToSleep )
  510. {    unused(howLongToSleep);
  511.     unsigned long sleepUntil = TickCount() + howLongToSleep;
  512.     
  513.     if ( TThread::GetCurrentThread() == this ) {
  514.         #if debug
  515.         if ( gThreadStatusWindow )
  516.             gThreadStatusWindow->InvalidateRow ( gThreadStatusWindowList.Find ( this ) );
  517.         #endif
  518.         
  519.         ThreadBeginCritical ();
  520.  
  521.         fWakeThreadAfter = TickCount() + howLongToSleep;
  522.         
  523.         gTickWhenNextThreadNeedsToBeWoken = min ( gTickWhenNextThreadNeedsToBeWoken, fWakeThreadAfter );
  524.         gSleepingThreads.Append ( this );
  525.         
  526.         SetThreadStateEndCritical ( fThreadID, kStoppedThreadState, kNoThreadID );
  527.         
  528.         #if debug
  529.         if ( gThreadStatusWindow )
  530.             gThreadStatusWindow->DrawRow ( gThreadStatusWindowList.Find ( this ) );
  531.         #endif        
  532.     }
  533. }
  534.  
  535. /***********************************|****************************************/
  536.  
  537. void TThreadManagerThread::Yield ( )
  538. {
  539.     if ( TThread::GetCurrentThread() == this ) {
  540.  
  541.         OSErr err = YieldToAnyThread ();
  542.         if ( err )
  543.             keithDB ( "TThreadManagerThread::YieldToAnyThread(), err=" << err );
  544.     }
  545. }
  546.  
  547. /***********************************|****************************************/
  548.  
  549. void TThreadManagerThread::Wake ( )
  550. {    
  551.     SetThreadState ( fThreadID, kReadyThreadState, kNoThreadID );
  552.     gSleepingThreads.Remove ( this );
  553.  
  554.     #if debug
  555.     if ( gThreadStatusWindow )
  556.         gThreadStatusWindow->DrawRow ( gThreadStatusWindowList.Find ( this ) );
  557.     #endif
  558. }
  559.  
  560. /***********************************|****************************************/
  561.  
  562. void* TThreadManagerThread::GetExceptionChain (void) const
  563. {
  564.     return fExceptionChainTop;
  565. }
  566.  
  567. /***********************************|****************************************/
  568.  
  569. void TThreadManagerThread::SetExceptionChain(void * chainTop )
  570. {
  571.     fExceptionChainTop = chainTop;
  572. }
  573.  
  574. /***********************************|****************************************/
  575. /***********************************|****************************************/
  576.  
  577. TThread* TThread::GetCurrentThread ( )
  578. {
  579.     return gCurrentThread;
  580. }
  581.  
  582. /***********************************|****************************************/
  583.  
  584. void TThread::YieldCurrentThread ( TThread* threadToYieldTo )
  585. {
  586.     unused(threadToYieldTo);
  587.     
  588.     GetCurrentThread()->Yield();
  589. }
  590.  
  591. /***********************************|****************************************/
  592.  
  593. unsigned long TThread::GetCurrentThreadStackSpace ()
  594. {    unsigned long stackSize = 0;
  595.     
  596.     OSErr err = ThreadCurrentStackSpace ( kCurrentThreadID, &stackSize );
  597.     
  598.     if ( err )
  599.         keith << "TThread::GetCurrentThreadStackSpace(), err = " << err << endl;
  600.     
  601.     return stackSize;
  602. }
  603.  
  604. /***********************************|****************************************/
  605.  
  606. void TThreadManagerThread::BeginCritical ( )
  607. {
  608.     ThreadBeginCritical ();
  609. }
  610.  
  611. /***********************************|****************************************/
  612.  
  613. void TThreadManagerThread::EndCritical ( )
  614. {
  615.     ThreadEndCritical ();
  616. }
  617.  
  618. /***********************************|****************************************/
  619.  
  620. OSType TThreadManagerThread::GetDescriptor ()
  621. {
  622.     return fDescriptor;
  623. }
  624.  
  625. /***********************************|****************************************/
  626.  
  627. unsigned long TThread::GetThreadCount ( )
  628. {
  629.     TThread* thread = gThreadList;
  630.     unsigned long threadCount = 0;
  631.     
  632.     while ( thread )
  633.     {
  634.         thread = thread->fNext;
  635.         ++threadCount;
  636.     }
  637.     
  638.     return threadCount;
  639. }
  640.  
  641. /***********************************|****************************************/
  642.  
  643. TThread * TThread::GetThread ( unsigned long index )
  644. {    
  645.     TThread * result = gThreadList;
  646.     while ( result && ( index > 1 ) ) {
  647.         result = result->fNext;
  648.         index --;
  649.     }
  650.     
  651.     return result;
  652. }
  653.  
  654. /***********************************|****************************************/
  655. /***********************************|****************************************/
  656. /***********************************|****************************************/
  657.  
  658. class TThreadManagerMainApplicationThread : public TThreadManagerThread
  659. {
  660.     public:
  661.                             TThreadManagerMainApplicationThread ( );
  662.     virtual                    ~TThreadManagerMainApplicationThread ();
  663.         
  664.     virtual    void            Sleep ( unsigned long howLongToSleep = 0 );
  665.     virtual void            Yield ( );
  666.     virtual void            Wake ( );
  667.  
  668.     virtual OSType            GetDescriptor();
  669. };
  670.  
  671. /***********************************|****************************************/
  672.  
  673. TThreadManagerMainApplicationThread::TThreadManagerMainApplicationThread () :
  674.     TThreadManagerThread ( 'MAIN' )
  675. {
  676.     fThreadID = kApplicationThreadID;
  677.  
  678.     //    The main thread doesn't need a terminator
  679.     SetThreadTerminator ( fThreadID, (ThreadTerminationProcPtr) nil, (void*) this );
  680.     gCurrentThread = this;
  681. }
  682.  
  683. /***********************************|****************************************/
  684.  
  685. TThreadManagerMainApplicationThread::~TThreadManagerMainApplicationThread ()
  686. {
  687.     // DebugStr ("\pTThreadManagerMainApplicationThread::~TThreadManagerMainApplicationThread()");
  688.     fThreadID = 0;
  689. }
  690.  
  691. /***********************************|****************************************/
  692.  
  693. void TThreadManagerMainApplicationThread::Sleep ( unsigned long /* howLongToSleep */ )
  694. {    
  695.     if ( gThreadStatusWindow )
  696.         gThreadStatusWindow->RedrawSleeping ();
  697.  
  698.     //    The Main Event Loop thread should never get put to sleep.
  699.     //    Instead, just yield to someone else.
  700.     YieldToAnyThread  ();
  701. }
  702.  
  703. /***********************************|****************************************/
  704.  
  705. void TThreadManagerMainApplicationThread::Yield ( )
  706. {
  707.     if ( gThreadStatusWindow )
  708.         gThreadStatusWindow->RedrawSleeping ();
  709.         
  710.     if ( TThread::GetCurrentThread() == this ) {
  711.         YieldToAnyThread ();
  712.     }
  713. }
  714.  
  715. /***********************************|****************************************/
  716.  
  717. void TThreadManagerMainApplicationThread::Wake ( )
  718. {
  719.     SetThreadState ( fThreadID, kReadyThreadState, kNoThreadID );
  720. }
  721.  
  722. /***********************************|****************************************/
  723.  
  724. OSType TThreadManagerMainApplicationThread::GetDescriptor ()
  725. {
  726.     return 'MAIN';
  727. }
  728.  
  729. /***********************************|****************************************/
  730.  
  731. TThread* gMainApplicationThread = nil;
  732.  
  733. /***********************************|****************************************/
  734.  
  735. void CreateMainApplicationThread ()
  736. {
  737.     //    Verify that the threads manager is installed.
  738.     long value;
  739.     if ( ( Gestalt ( gestaltThreadMgrAttr, &value ) != noErr ) || ( (value & ( 1 << gestaltThreadMgrPresent)) == 0 ) )
  740.     {
  741.         #if debug
  742.         DebugStr ("\pThe Threads Manager extension must be installed to use this gateway.");
  743.         #endif 
  744.     
  745.         ExitToShell();
  746.     }
  747.     
  748.     gMainApplicationThread = new TThreadManagerMainApplicationThread();
  749. }
  750.  
  751. /***********************************|****************************************/
  752.  
  753. void TThreadManagerThread::WakeUpSleepingThreadsTask ( )
  754. {
  755.     if ( gTickWhenNextThreadNeedsToBeWoken <= TickCount() )
  756.     {
  757.         //    If we're currently in some thread,
  758.         if ( GetCurrentThread() )
  759.         {
  760.             //    Then don't let anything weird happen for a little while.
  761.             GetCurrentThread()->BeginCritical () ;
  762.             
  763.             //    Step through all of the threads, waking any thread that should 
  764.             //    be woken up.
  765.             gTickWhenNextThreadNeedsToBeWoken = LONG_MAX;
  766.             for ( unsigned long i = gSleepingThreads.Count(); i > 0;  -- i )
  767.             {    TThreadManagerThread * thread = gSleepingThreads.Get ( i );
  768.             
  769.                 if ( thread && thread->fWakeThreadAfter <= TickCount() )
  770.                     thread->Wake ( );
  771.                 else
  772.                     gTickWhenNextThreadNeedsToBeWoken = min ( thread->fWakeThreadAfter, gTickWhenNextThreadNeedsToBeWoken ); 
  773.             }
  774.             
  775.             //    And let the world be happy again.
  776.             GetCurrentThread()->EndCritical ();
  777.         }
  778.     }
  779. }
  780.  
  781. /***********************************|****************************************/
  782. /***********************************|****************************************/
  783.  
  784. void ShowAllThreadStatus ( ostream& s )
  785. {
  786.     s << "Thread Status: (" << TThread::GetThreadCount() << " total, " <<
  787.             gSleepingThreads.Count() << " sleeping)" << endl;
  788.  
  789.     for ( unsigned long i = 1; i <= TThread::GetThreadCount(); ++ i )
  790.     {
  791.         TThread * t = TThread::GetThread ( i );
  792.         
  793.         if ( t )
  794.         {
  795.             s << " ";
  796.             s.width(3);
  797.             s << i << ") "; t->operator << ( s ); s   << endl;
  798.         }
  799.     }
  800. }
  801.  
  802. /***********************************|****************************************/
  803. /***********************************|****************************************/
  804. /***********************************|****************************************/
  805.  
  806.  
  807. /***********************************|****************************************/
  808.  
  809. TThreadStatusWindow::TThreadStatusWindow ( short windowID ) :
  810.     TLogWindow ( windowID )
  811. {
  812. }
  813.  
  814. /***********************************|****************************************/
  815.  
  816. TThreadStatusWindow::~TThreadStatusWindow ()
  817. {
  818. }
  819.  
  820. /***********************************|****************************************/
  821.  
  822. void TThreadStatusWindow::Show () const
  823. {
  824.     TLogWindow::Show ();
  825.     
  826.     CGrafPortSaver portSaver ( GetWindowPtr () );
  827.     TextFont ( 1 );
  828.     TextSize ( 10 );
  829.     TextFace ( 0 );
  830.     TextMode ( srcCopy );
  831. }
  832.  
  833. /***********************************|****************************************/
  834.  
  835. unsigned long TThreadStatusWindow::GetRowCount () const
  836. {
  837.     return TThread::GetThreadCount () + 1;
  838. }
  839.  
  840. /***********************************|****************************************/
  841.  
  842. void TThreadStatusWindow::DrawRow ( unsigned long whichRow ) const
  843. {
  844.     CGrafPortSaver saver ( fDebugWindowPtr );
  845.     Rect r = GetRectForRow ( whichRow );
  846.     short x = r.left;
  847.     short baseY = r.bottom - 2;
  848.  
  849.     const short kDescriptorOffset = 2;
  850.     const short kStateOffset = 50;
  851.     const short kSleepingUntilOffset = 100;
  852.     const short kStackSizeOffset = 160;
  853.     
  854.     if ( whichRow == 1 )
  855.     {        
  856.         DrawString ( x + kDescriptorOffset, baseY, "\pThread" );
  857.         EraseLineToDrawString ( x + kStateOffset, baseY, "\pState" );
  858.         EraseLineToDrawString ( x + kSleepingUntilOffset, baseY, "\pUntil" );
  859.         EraseLineToDrawString ( x + kStackSizeOffset, baseY, "\pStack space" );
  860.         EraseLineToDrawString ( (short) x + GetRowWidth(), baseY, "\p" );
  861.          
  862.         return;
  863.     }
  864.     
  865.     #if 1
  866.     
  867.     TThreadManagerThread* t = (TThreadManagerThread*) TThread::GetThread ( whichRow - 1);
  868.  
  869.     if ( t )
  870.     {
  871.         MoveTo ( x + kDescriptorOffset, baseY );
  872.         DrawText ( (Ptr) & t->fDescriptor , 0, sizeof ( t->fDescriptor ) );
  873.         
  874.         ThreadState state;
  875.         
  876.         if ( GetThreadState ( t->fThreadID, & state ) != noErr )
  877.             state = (ThreadState) 0xffff;
  878.             
  879.         switch ( state )
  880.         {
  881.             case kRunningThreadState:
  882.                 EraseLineToDrawString ( x + kStateOffset, baseY, "\pRunning" );
  883.                 break;
  884.  
  885.             case kReadyThreadState:        
  886.                  EraseLineToDrawString ( x + kStateOffset, baseY, "\pReady");
  887.                  break;
  888.                  
  889.             case kStoppedThreadState:
  890.                  EraseLineToDrawString ( x + kStateOffset, baseY, "\pStopped" );
  891.  
  892.                  EraseLineToDrawNumber ( x + kSleepingUntilOffset, baseY, TicksUntil ( t->fWakeThreadAfter ) / 60 );
  893.                  DrawString ("\p secs");
  894.                  
  895.                  break;
  896.                  
  897.             default:
  898.                 EraseLineToDrawString ( x + kStateOffset, baseY, "\p?" );
  899.                 break;
  900.         };
  901.         
  902.         unsigned long stackSize;
  903.         if ( ThreadCurrentStackSpace ( t->fThreadID, & stackSize ) == noErr )
  904.             EraseLineToDrawNumber ( x + kStackSizeOffset, baseY, stackSize );
  905.     }
  906.     else
  907.     {
  908.         EraseRect ( &r );
  909.     }    
  910.     
  911.     #else
  912.         
  913.     TThread* t;
  914.     
  915.     t = TThread::GetThread ( whichRow );
  916.     
  917.     if ( t )
  918.     {    strstream text;
  919.         
  920.         t->operator << ( text );
  921.         DrawText ( text.str(), 0, strlen ( text.str() ) );
  922.     }
  923.     #endif
  924. }
  925.  
  926. /***********************************|****************************************/
  927.  
  928. void TThreadStatusWindow::RedrawSleeping ( ) const
  929. {
  930.     for ( unsigned int i = 1; i <= GetRowCount() ; ++ i )
  931.         DrawRow ( i );
  932. }
  933.  
  934. /***********************************|****************************************/
  935.  
  936. unsigned long TThreadStatusWindow::GetRowWidth ( ) const
  937. {
  938.     return 300;
  939. }
  940.  
  941. /***********************************|****************************************/
  942.